package com.baosight.risk.service.fltd.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.runtime.ProcessInstanceQuery;
import org.activiti.engine.task.Task;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import com.baosight.iplat4j.core.ei.EiConstant;
import com.baosight.iplat4j.core.ei.EiInfo;
import com.baosight.iplat4j.core.service.soa.XLocalManager;
import com.baosight.risk.api.fltd.AuthoTypeService;
import com.baosight.risk.api.fltd.FlaaFlowCheckService;
import com.baosight.risk.api.fltd.FlaaNodeAuthoService;
import com.baosight.risk.api.fltd.FlaaNodeService;
import com.baosight.risk.api.fltd.FltdNoticeService;
import com.baosight.risk.api.fltd.FltdOATaskService;
import com.baosight.risk.api.fltd.FltdProcessService;
import com.baosight.risk.api.fltd.FltdTaskService;
import com.baosight.risk.api.workflow.AfterHandler;
import com.baosight.risk.api.workflow.BeforeHandler;
import com.baosight.risk.api.workflow.UpdateHandler;
import com.baosight.risk.api.xtaa.calendar.IXtaaCalendarService;
import com.baosight.risk.api.xtzy.IXtzyUserService;
import com.baosight.risk.base.redis.BaseRedis;
import com.baosight.risk.common.annotation.Log;
import com.baosight.risk.common.aspects.factory.AsyncFactory;
import com.baosight.risk.common.bean.BeanUtils;
import com.baosight.risk.common.constant.WorkflowConstant;
import com.baosight.risk.common.enums.IntegralType;
import com.baosight.risk.common.manager.AsyncManager;
import com.baosight.risk.common.utils.DateUtils;
import com.baosight.risk.common.utils.ShiroUtils;
import com.baosight.risk.common.utils.StringUtils;
import com.baosight.risk.mapper.fltd.FltdProcessMapper;
import com.baosight.risk.mapper.fltd.FltdTaskMapper;
import com.baosight.risk.mapper.fltd.Tewpd01Mapper;
import com.baosight.risk.service.fltd.entity.FltdProcess;
import com.baosight.risk.service.fltd.entity.FltdTask;
import com.baosight.risk.service.fltd.entity.Tewpd01;
import com.baosight.risk.service.fltd.vo.FlaaFlowCheckVO;
import com.baosight.risk.service.fltd.vo.FlaaNodeAuthoTypeVO;
import com.baosight.risk.service.fltd.vo.FlaaNodeAuthoVO;
import com.baosight.risk.service.fltd.vo.FlaaNodeVO;
import com.baosight.risk.service.fltd.vo.FltdProcessVO;
import com.baosight.risk.service.fltd.vo.FltdTaskVO;
import com.baosight.risk.service.fltd.vo.NodeTransitionVO;
import com.baosight.risk.service.system.entity.SysOperLog;
import com.baosight.risk.service.xtzy.entity.XtzyCompany;
import com.baosight.risk.service.xtzy.entity.XtzyUser;
import com.baosight.risk.web.netty.SocketIO;

/**
 * 作者： lishaoqing
 * 时间： 2019年07月19日
 * 描述： FltdProcessServiceImpl
 * 版本: v1.0
 */
@Service("fltdProcessServiceImpl")
public class FltdProcessServiceImpl implements FltdProcessService {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private FltdProcessMapper fltdProcessMapper;

    @Autowired
    private Tewpd01Mapper tewpd01Mapper;

    @Autowired
    private FlaaNodeAuthoService flaaNodeAuthoService;

    @Autowired
    private FltdTaskService fltdTaskService;

    @Autowired
    private FlaaFlowCheckService flaaFlowCheckService;

    @Autowired
    private FlaaNodeService flaaNodeService;

    @Autowired
    private FltdNoticeService fltdNoticeService;

    @Autowired
    private IXtzyUserService xtzyUserService;

    @Autowired
    private IXtaaCalendarService xtaaCalendarService;

    @Autowired
    private AuthoTypeService authoTypeService;

    @Autowired
    private SocketIO socketServer;

    @Autowired
    private BaseRedis baseRedis;
    @Autowired
    private FltdTaskMapper fltdTaskMapper;
    @Autowired
    private FltdOATaskService fltdOATaskService;

    private RuntimeService getRuntimeService() {
        return ProcessEngines.getDefaultProcessEngine().getRuntimeService();
    }

    private TaskService getTaskService() {
        return ProcessEngines.getDefaultProcessEngine().getTaskService();
    }


    @Override
    public Integer insert(FltdProcess fltdProcess) {
        return fltdProcessMapper.insert(fltdProcess);
    }

    @Override
    public FltdProcess selectProcessById(String procGuid) {
        return fltdProcessMapper.selectProcessById(procGuid);
    }

    @Override
    public List<FltdProcessVO> list(FltdProcessVO fltdProcess) {
        return fltdProcessMapper.queryAll(fltdProcess);
    }

    @Override
    public List<Tewpd01> getAllProcess() {
        return tewpd01Mapper.getAllProcess();
    }

    /**
     * 获取流程启动人
     */
    @Override
    public XtzyUser getStarter() {
        //流程启动人
        XtzyUser starter = null;
        boolean error = false;
        try {
            starter = ShiroUtils.getUser();
        } catch (Exception e) {
            error = true;
        }
        if (error || starter == null) {
            starter = xtzyUserService.selectByName(WorkflowConstant.DEFALT_STARTER);
        }
        return starter;
    }

    @Override
    public void doStart(FltdTaskVO vo) throws Exception {
        try {
            Date now = null;
            //流程启动人
            XtzyUser starter = getStarter();
            //下发节点权限验证
            Map<String, Object> validMap = flaaNodeAuthoService.validStart(vo, starter);
            String code = (String) validMap.get("code");
            if ("1".equals(code)) {
                throw new Exception("流程未授权！");
            } else if ("2".equals(code)) {
                throw new Exception("用户无权限启动此流程！");
            } else {
                //启动流程实例
                Map<String, Object> resultMap = startProcess(starter, vo.getFlowNo(), vo.getVariables());
                String processInstanceId = (String) resultMap.get("processInstanceId");
                if (StringUtils.isEmpty(processInstanceId)) {
                    throw new Exception("流程启动异常！");
                }

                //第一个人工节点的授权信息
                FlaaNodeAuthoVO firstNode = (FlaaNodeAuthoVO) validMap.get("firstNode");

                //记录流程实例表
                now = new Date();
                FltdProcess fltdProcess = new FltdProcess();
                //转换bean
                BeanUtils.copyBeanProp(fltdProcess, vo);
                fltdProcess.setProcGuid(processInstanceId);
                fltdProcess.setFactStartDate(now);
                fltdProcess.setNodeCode(firstNode.getNodeCode());
                fltdProcess.setNodeName(firstNode.getNodeName());
                fltdProcess.setAcctYear(vo.getAcctYear());
                fltdProcess.setQuarterCode(vo.getQuarterCode());
                fltdProcess.setQuarterName(vo.getQuarterName());
                fltdProcess.setDeptCode(vo.getDeptCode());
                fltdProcess.setDeptName(vo.getDeptName());
                fltdProcess.setCreateBy(starter.getUserCode());
                fltdProcess.setCreateTime(now);
                Integer insert = insert(fltdProcess);
                if (insert == 0) {
                    throw new Exception("数据库操作失败");
                }

                //开始节点，添加一条已完成的待办记录，不发送待办提醒
                vo.setProcGuid(processInstanceId);
                vo.setStatus("finish");
                vo.setStatusName("关闭");
                List<XtzyUser> users = new ArrayList<>();
                users.add(starter);
                Map<String, Object> taskMap = createTask(firstNode, vo, starter, users, "N", "start", null);
                if (taskMap == null) {
                    throw new Exception("数据库操作失败");
                }

                //直接提交第一个节点
                FltdTask task = (FltdTask) taskMap.get(starter.getUserCode());
                if (task == null) {
                    throw new Exception("待办下发失败");
                }
                FltdTaskVO submitvo = new FltdTaskVO();
                BeanUtils.copyBeanProp(submitvo, task);
                if (CollectionUtils.isNotEmpty(vo.getCustomUsers())) {
                    submitvo.setExt5("Y");
                }
                try {
                    //获取第二个节点的审批人
                    Map<String, Object> userMap = flaaNodeAuthoService.getNextUser(submitvo, starter);
                    NodeTransitionVO submitButton = (NodeTransitionVO) userMap.get("submitTransition");
                    List<XtzyUser> nextUsers = null;
                    if (CollectionUtils.isNotEmpty(vo.getCustomUsers())) {
                        nextUsers = vo.getCustomUsers();
                    } else {
                        nextUsers = (List<XtzyUser>) userMap.get("authUsers");
                    }
                    submitvo.setSubmitButton(submitButton);
                    submitvo.setCustomUsers(nextUsers);
                    //提交第一个节点
                    doSubmit(starter, submitvo);
                }catch (Exception e) {
                    throw new Exception("提交第一个人工节点异常！"+e.getMessage());
                }
            }
        } catch (Exception ex) {
            throw new Exception("流程启动异常："+ ex.getMessage());
        }
    }

    @Override
    @Transactional
    public void doSubmit(XtzyUser user, FltdTaskVO taskVO) throws Exception {
        try {//+ taskVO.getProcGuid()
            if (baseRedis.louck(user.getUserCode() + taskVO.getBizGuid() + taskVO.getProcGuid())) {
                //提交流程前验证
                Map<String, Object> resultMap = preSubmit(taskVO, user);
                if (!"0".equals(resultMap.get("code"))) {
                    throw new Exception((String) resultMap.get("msg"));
                }
                //当前待办
                FltdTask currentTask = (FltdTask) resultMap.get("currentTask");
                String decideType = selectDecideType((String) resultMap.get("processDefId"), currentTask.getNodeCode());
                if (StringUtils.isEmpty(decideType)) {
                    throw new Exception("流程异常！未找到流程定义id，processDefId：" + resultMap.get("processDefId"));
                } else if ("0".equals(decideType)) {
                    // 一个人提交即通过（常用）
                    System.out.println("一个人提交即通过");
                    normalSubmit(user, taskVO, resultMap, currentTask);
                } else {
                    // 所有人提交才通过（特殊）
                    if (StringUtils.isNotEmpty(currentTask.getProcGuid())
                            && StringUtils.isNotEmpty(currentTask.getNodeCode())
                            && StringUtils.isNotEmpty(currentTask.getCurrUserCode())) {
                        // 查询当前节点是否还有其他人未提交的待办
                        if (fltdTaskService.selectCanSubmit(currentTask.getProcGuid(), currentTask.getNodeCode(), currentTask.getCurrUserCode())) {
                            // 当前节点所有人都提交了
                            System.out.println("当前节点所有人都提交了");
                            lastPass(user, taskVO, resultMap, currentTask);
                        } else {
                            // 还有人没提交
                            System.out.println("还有人没提交");
                            singlePass(user, taskVO, resultMap, currentTask);
                        }
                    } else {
                        throw new Exception("当前待办不符合流程，请检查待办数据！");
                    }
                }
            }
        } catch (Exception e) {
            throw new Exception("操作异常："+e.getMessage());
        } finally {
            baseRedis.unLouck(user.getUserCode() + taskVO.getBizGuid());
        }

    }

    /**
     * 单人提交（所有人提交才通过）
     *
     */
    public void singlePass(XtzyUser user, FltdTaskVO taskVO, Map<String, Object> resultMap, FltdTask currentTask) throws Exception {
        List<XtzyUser> noticesList = new ArrayList<>();
        noticesList.add(user);
        try {

            //添加当前审批人审计意见
            addContext(user, taskVO, resultMap, currentTask);

            //提交流程
            submitCurrentNode(resultMap);

            //发送通知
            sendNotice(noticesList);

        } catch (Exception e) {
            throw new Exception("提交异常："+e.getMessage());
        }
    }

    /**
     * 最后一个人提交（所有人提交才通过）
     *
     */
    public void lastPass(XtzyUser user, FltdTaskVO taskVO, Map<String, Object> resultMap, FltdTask currentTask) throws Exception {
        Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap = new HashMap<>();
        Map<String, Object> params = new HashMap<>();
        List<XtzyUser> noticesList = new ArrayList<>();
        noticesList.add(user);
        try {
            //修改流程实例表状态
            upgradeProcessStatus(user, resultMap, currentTask);

            //提交类型
            String submitType = updateEndProcess(user, resultMap, currentTask);

            //添加当前审批人审计意见
            addContext(user, taskVO, resultMap, currentTask);

            //下发待办
            String nextSubmitType = createNextTasks(user, taskVO, resultMap, currentTask, noticesList);
            if (StringUtils.isNotEmpty(nextSubmitType)) {
                submitType = nextSubmitType;
            }

            //查询当前节点的事件配置
            nodeHandlerMap = getNodeHandler(currentTask.getFlowNo(), currentTask.getNodeCode());
            params = handleEvent(taskVO, resultMap, currentTask, submitType, nodeHandlerMap);

            //提交流程
            submitCurrentNode(resultMap);

            //提交后的处理(暂定为同步操作)
            afterSubmit(nodeHandlerMap, params);

            // 只有提交时才下发阅知提醒
            if(WorkflowConstant.COMMENT_SUBMIT.equals(resultMap.get("approvalResult"))) {
                //下发阅知提醒
                createNextRemind(user, currentTask, (FlaaNodeAuthoVO) resultMap.get("nodeInfo"));
            }

            //发送通知
            sendNotice(noticesList);

        } catch (Exception e) {
            throw new Exception("提交异常：" + e.getMessage());
        }

    }

    /**
     * 提交流程的所有步骤
     *
     */
    public void normalSubmit(XtzyUser user, FltdTaskVO taskVO, Map<String, Object> resultMap, FltdTask currentTask) throws Exception {
        Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap = new HashMap<>();
        Map<String, Object> params = new HashMap<>();
        List<XtzyUser> noticesList = new ArrayList<>();

        //修改流程实例表状态
        upgradeProcessStatus(user, resultMap, currentTask);

        //提交类型
        String submitType = updateEndProcess(user, resultMap, currentTask);

        //当前节点所有待办添加到通知列表
        unionAllTask(noticesList, currentTask);

        //关闭当前节点其他人的待办
        finishOtherTask(user, currentTask);

        //添加当前审批人审计意见
        addContext(user, taskVO, resultMap, currentTask);

        //下发待办
        String nextSubmitType = createNextTasks(user, taskVO, resultMap, currentTask, noticesList);
        if (StringUtils.isNotEmpty(nextSubmitType)) {
            submitType = nextSubmitType;
        }

        //查询当前节点的事件配置
        nodeHandlerMap = getNodeHandler(currentTask.getFlowNo(), currentTask.getNodeCode());
        params = handleEvent(taskVO, resultMap, currentTask, submitType, nodeHandlerMap);

        //提交流程
        submitCurrentNode(resultMap);

        //提交后的处理(暂定为同步操作)
        afterSubmit(nodeHandlerMap, params);
        if(taskVO.getVariables()!=null&&taskVO.getVariables().get("quartzParam")!=null&&"1".equals(taskVO.getVariables().get("quartzParam").toString())){

        }else{
            // 只有提交时才下发阅知提醒
            if(WorkflowConstant.COMMENT_SUBMIT.equals(resultMap.get("approvalResult"))) {
                //下发阅知提醒
                createNextRemind(user, currentTask, (FlaaNodeAuthoVO) resultMap.get("nodeInfo"));
            }
        }


        //发送通知
        sendNotice(noticesList);



    }

    /**
     * 修改流程实例表状态
     *
     */
    private void upgradeProcessStatus(XtzyUser user, Map<String, Object> resultMap, FltdTask currentTask) throws Exception {
        Date now = new Date();
        FltdProcess updateProcess = new FltdProcess();
        updateProcess.setProcGuid(currentTask.getProcGuid());
        NodeTransitionVO nextTransition = (NodeTransitionVO) resultMap.get("nextTransition");
        updateProcess.setNodeCode(nextTransition.getNodeKey());
        updateProcess.setNodeName(nextTransition.getNodeName());
        if ("1".equals(resultMap.get("isEnd"))) {
            updateProcess.setFactEndDate(now);
        }
        updateProcess.setUpdateBy(user.getUserCode());
        updateProcess.setUpdateTime(now);
        int result = updateProcessStatus(updateProcess);
        if (result == 0) {
            throw new Exception("数据库操作异常");
        }
    }

    /**
     * 判断下一个节点是不是结束节点
     *
     */
    private String updateEndProcess(XtzyUser user, Map<String, Object> resultMap, FltdTask currentTask) throws Exception {
        String submitType = "";
        //下一个节点是结束节点
        if ("1".equals(resultMap.get("isEnd"))) {
            //添加一条流程结束的待办记录
            NodeTransitionVO nextTransition = (NodeTransitionVO) resultMap.get("nextTransition");
            submitType = "end";
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND, 10);
            FltdTask endTask = new FltdTask();
            BeanUtils.copyBeanProp(endTask, currentTask);
            endTask.setTodoGuid(UUID.randomUUID().toString());
            endTask.setNodeCode(nextTransition.getNodeKey());
            endTask.setNodeName(nextTransition.getNodeName());
            endTask.setBeforeNodeCode(currentTask.getNodeCode());
            endTask.setBeforeNodeName(currentTask.getNodeName());
            endTask.setBeforeUserCode(user.getUserCode());
            endTask.setBeforeUserName(user.getUserDesc());
            endTask.setAuditCode(user.getUserCode());
            endTask.setAuditName(user.getUserDesc());
            endTask.setStatus("close");
            endTask.setStatusName("完成");
            endTask.setFactStartDate(calendar.getTime());
            endTask.setFactEndDate(calendar.getTime());
            endTask.setContext(null);
            endTask.setPageUrl(null);
            endTask.setRemark(WorkflowConstant.COMMENT_FINISH);
            endTask.setExt1("3");
            endTask.setExt2(WorkflowConstant.COMMENT_FINISH);
            endTask.setCreateBy(user.getUserCode());
            endTask.setCreateTime(calendar.getTime());
            endTask.setUpdateBy(user.getUserCode());
            endTask.setUpdateTime(calendar.getTime());
            int result = fltdTaskService.insert(endTask);
            if (result == 0) {
                throw new Exception("数据库操作异常");
            }
        }
        return submitType;
    }

    /**
     * 把当前节点所有待办处理人添加到通知列表
     *
     */
    private void unionAllTask(List<XtzyUser> noticesList, FltdTask currentTask) throws Exception {
        //当前节点所有待办
        List<FltdTask> fltdTasks = fltdTaskService.selectCurrentTasks(currentTask.getProcGuid(), currentTask.getNodeCode());
        List<XtzyUser> list = new ArrayList<>();
        for (FltdTask fltdTask : fltdTasks) {
            XtzyUser xtzyUser = new XtzyUser();
            xtzyUser.setUserCode(fltdTask.getCurrUserCode());
            xtzyUser.setExt1(fltdTask.getDeptCode());
            if (currentTask.getCurrUserCode().equals(fltdTask.getCurrUserCode())){
                //自己的小铃铛不弹出提醒
                xtzyUser.setExt3("close");
            }else{
                xtzyUser.setExt3("open");
            }
            list.add(xtzyUser);
        }
        //合并消息通知列表
        unionUsers(noticesList, list);
    }

    /**
     * 关闭当前节点其他人的待办
     *
     */
    private void finishOtherTask(XtzyUser user, FltdTask currentTask) throws Exception {
        //关闭当前节点其他人的待办
        Date now = new Date();
        FltdTask instTask = new FltdTask();
        instTask.setProcGuid(currentTask.getProcGuid());
        instTask.setNodeCode(currentTask.getNodeCode());
        instTask.setStatus("finish");
        instTask.setStatusName("关闭");
        instTask.setBeforeNodeCode(currentTask.getNodeCode());
        instTask.setBeforeNodeName(currentTask.getNodeName());
        instTask.setAuditCode(user.getUserCode());
        instTask.setAuditName(user.getUserDesc());
        instTask.setFactEndDate(now);
        instTask.setUpdateBy(user.getUserCode());
        instTask.setUpdateTime(now);
        instTask.setExt5(user.getUserCode());
        fltdTaskService.updateTaskStatus(instTask);
    }

    /**
     * 添加当前审批人审计意见
     *
     */
    private void addContext(XtzyUser user, FltdTaskVO taskVO, Map<String, Object> resultMap, FltdTask currentTask) throws Exception {
        //添加当前审批人审计意见
        Date now = new Date(System.currentTimeMillis() + 1000);
        String approvalResult = (String) resultMap.get("approvalResult");
        FltdTask fltdTask = new FltdTask();
        fltdTask.setTodoGuid(currentTask.getTodoGuid());
        fltdTask.setStatus("close");
        fltdTask.setStatusName("完成");
        fltdTask.setAuditCode(user.getUserCode());
        fltdTask.setAuditName(user.getUserDesc());
        fltdTask.setContext(taskVO.getContext());
        fltdTask.setRemark(approvalResult);
        fltdTask.setFactEndDate(now);
        fltdTask.setUpdateBy(user.getUserCode());
        fltdTask.setUpdateTime(now);
        int result = fltdTaskService.updateTaskStatus(fltdTask);
        if (result == 0) {
            throw new Exception("数据库操作异常");
        }
    }

    /**
     * 下发待办、设置催办等
     *
     */
    private String createNextTasks(XtzyUser user, FltdTaskVO taskVO, Map<String, Object> resultMap, FltdTask currentTask, List<XtzyUser> noticesList ) throws Exception {
        NodeTransitionVO nextTransition = (NodeTransitionVO) resultMap.get("nextTransition");
        FlaaNodeAuthoVO nodeInfo = (FlaaNodeAuthoVO) resultMap.get("nodeInfo");
        String approvalResult = (String) resultMap.get("approvalResult");
        String submitType = "";
        List<XtzyUser> userList = (List<XtzyUser>) resultMap.get("userList");
        //todo 提交关闭之前oa待办 正式暂时关闭删除OA待办
        try {
            fltdOATaskService.deleteOA(currentTask);
        }catch (Exception e){
            throw new Exception("删除oa待办失败："+e.getMessage());
        }
        if (!"1".equals(resultMap.get("isEnd"))) {
            String greeFlag = "N";
            String transitionKey = nextTransition.getTransitionKey();
            if (transitionKey.indexOf("return-G") >= 0) {
                //绿色通道回退
                greeFlag = "G";
            }

            //给下一节点审批人发待办
            if (userList != null && userList.size() > 0) {
                FltdTaskVO vo = new FltdTaskVO();
                BeanUtils.copyBeanProp(vo, currentTask);
                vo.setBeforeNodeCode(currentTask.getNodeCode());
                vo.setBeforeNodeName(currentTask.getNodeName());
                vo.setBeforeUserCode(user.getUserCode());
                vo.setBeforeUserName(user.getUserDesc());
                if (!ObjectUtils.isEmpty(nodeInfo.getPageUrl())){
                    vo.setPageUrl(nodeInfo.getPageUrl());
                }

                if (WorkflowConstant.COMMENT_SUBMIT.equals(approvalResult)) {
                    submitType = "sbumit";
                        vo.setRemark(WorkflowConstant.COMMENT_SUBMIT);
                    vo.setExt1("1");
                    vo.setExt2(WorkflowConstant.COMMENT_SUBMIT);
                } else if (WorkflowConstant.COMMENT_REJECT.equals(approvalResult)) {
                    submitType = "reject";
                    vo.setRemark(WorkflowConstant.COMMENT_REJECT);
                    vo.setExt1("2");
                    vo.setExt2(WorkflowConstant.COMMENT_REJECT);
                }

                //查询催办配置
                FlaaNodeVO urgent = flaaNodeService.selectUrgent(currentTask.getFlowNo(), nodeInfo.getNodeCode());
                if (!ObjectUtils.isEmpty(urgent) && urgent.getPressDay() != null && urgent.getPressDay() > 0) {
                    //设置催办时间
                    Calendar calendar = Calendar.getInstance();
                    calendar.add(Calendar.DAY_OF_MONTH, 1);
                    Date startDate = calendar.getTime();
                    String time = xtaaCalendarService.selectCalendarByDataAndTime(DateUtils.formatYYYY_MM_DD(startDate), urgent.getPressDay());
                    Date endDate = DateUtils.parse(time, DateUtils.YYYY_MM_DD);
                    vo.setPlanStartDate(startDate);
                    vo.setPlanEndDate(endDate);
                    vo.setPressFlag("Y");
                    vo.setPressNum(0);
                }

                Map<String, Map<String, String>> userAuthoMap = null;
                if (WorkflowConstant.COMMENT_SUBMIT.equals(resultMap.get("approvalResult"))){
                    userAuthoMap = getUserAuthoInfo(nodeInfo, user, taskVO);
                }

                //下发待办
                Map<String, Object> taskMap = createTask(nodeInfo, vo, user, userList, greeFlag, "submit", userAuthoMap);
                if (taskMap == null) {
                    throw new Exception("数据库操作失败");
                }

                for (XtzyUser xtzyUser : userList) {
                    xtzyUser.setExt3("open");
                }
                //合并消息通知列表
                unionUsers(noticesList, userList);

            } else {
                throw new Exception("未找到下一个节点审批人，bizName：" + currentTask.getBizName());
            }
        }
        return submitType;
    }

    /**
     * 发送通知提醒
     *
     */
    private void createNextRemind(XtzyUser user, FltdTask currentTask, FlaaNodeAuthoVO nodeInfo) throws Exception {
        try {
            if (nodeInfo != null) {
                FltdTaskVO vo = new FltdTaskVO();
                BeanUtils.copyBeanProp(vo, currentTask);
                Map<String, Object> map = flaaNodeAuthoService.getUsersByNodeInfo(nodeInfo, user, vo);
                List<XtzyUser> remindUsers = (List<XtzyUser>) map.get("remindUsers");
                if (CollectionUtils.isNotEmpty(remindUsers)) {
                    for (XtzyUser remindUser : remindUsers) {
                        FltdTask remind = (FltdTask) BeanUtils.initBean(new FltdTask());
                        BeanUtils.initExt(remind);
                        BeanUtils.copyBeanProp(remind, currentTask);
                        remind.setTodoGuid(UUID.randomUUID().toString());
                        remind.setTodoType("2");
                        remind.setStatus("open");
                        remind.setStatusName("进行中");
                        remind.setFactStartDate(new Date());
                        remind.setFirstUserCode(remindUser.getUserCode());
                        remind.setFirstUserName(remindUser.getUserDesc());
                        remind.setBeforeUserCode(currentTask.getCurrUserCode());
                        remind.setBeforeUserName(currentTask.getCurrUserName());
                        remind.setCurrUserCode(remindUser.getUserCode());
                        remind.setCurrUserName(remindUser.getUserDesc());
                        remind.setGroupFlag("N");
                        remind.setAcctYear(currentTask.getAcctYear());
                        remind.setQuarterCode(currentTask.getQuarterCode());
                        remind.setQuarterName(currentTask.getQuarterName());
                        remind.setDeptCode(currentTask.getDeptCode());
                        remind.setDeptName(currentTask.getDeptName());
                        remind.setCompCode(currentTask.getCompCode());
                        remind.setCompName(currentTask.getCompName());
                        remind.setBizGuid(currentTask.getBizGuid());
                        remind.setBizName(currentTask.getBizName());
                        remind.setBizDesc(remindUser.getRemark());

                        if (fltdTaskService.insert(remind) > 0) {
                            // 发送通知
                            XtzyUser userMsg = new XtzyUser();
                            userMsg.setUserCode(remindUser.getUserCode());
                            userMsg.setUserDesc(remindUser.getUserDesc());
                            userMsg.setExt1(currentTask.getDeptCode());
                            userMsg.setExt2(currentTask.getDeptName());
                            userMsg.setExt3("open");
                            //socketServer.sendMsgToAll(userMsg);
                        }

                    }
                }
            }
        } catch (Exception e) {
            throw new Exception("下发阅知提醒失败：" + e.getMessage());
        }

    }

    /**
     * 当前节点配置的事件处理
     *
     */
    private Map<String, Object> handleEvent(FltdTaskVO taskVO, Map<String, Object> resultMap, FltdTask currentTask, String submitType, Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap) throws Exception {
        NodeTransitionVO nextTransition = (NodeTransitionVO) resultMap.get("nextTransition");
        FlaaNodeAuthoVO nodeInfo = (FlaaNodeAuthoVO) resultMap.get("nodeInfo");
        Map<String, Object> params = new HashMap<>();
        //事件的参数
        params.put("status", currentTask.getNodeCode());
        if ("1".equals(resultMap.get("isEnd"))) {
            params.put("nextStatus", nextTransition.getNodeKey());
            params.put("nextStatusName", nextTransition.getNodeName());
        } else {
            params.put("nextStatus", nodeInfo.getNodeCode());
            params.put("nextStatusName", nodeInfo.getNodeName());
        }
        params.put("acctYear", currentTask.getAcctYear());
        params.put("quarterCurrent", currentTask.getQuarterCode());
        params.put("deptCode", currentTask.getDeptCode());
        params.put("bizGuid", currentTask.getBizGuid());
        params.put("bizName", currentTask.getBizName());
        params.put("taskGuid", currentTask.getTaskGuid());
        params.put("context", taskVO.getContext());
        params.put("submitType", submitType);
        if(taskVO.getVariables()!=null && taskVO.getVariables().get("quartzParam")!=null){
            params.put("quartzParam", taskVO.getVariables().get("quartzParam"));
            params.put("currentExaminerCode", taskVO.getVariables().get("currentExaminerCode"));
            params.put("currentExaminerName", taskVO.getVariables().get("currentExaminerName"));
        }
        //前置处理
        if (!beforeHandle(nodeHandlerMap, params)) {
            throw new Exception("前置处理异常！");
        }

        //状态修改
        if (!updateHandle(nodeHandlerMap, params)) {
            throw new Exception("状态修改异常！");
        }
        return params;
    }

    /**
     * 提交流程
     *
     */
    private void submitCurrentNode(Map<String, Object> resultMap) throws Exception {
        //提交当前流程
        List<Map<String, Object>> submitList = (List<Map<String, Object>>) resultMap.get("submitList");
        EiInfo eiinfo = submitProcess(submitList);
        if (eiinfo.getStatus()!=1) {
            throw new Exception("流程提交异常:"+eiinfo.getMsg());
        }
    }

    /**
     * 发送通知
     *
     */
    private void sendNotice(List<XtzyUser> noticesList) throws Exception {
/*        //发送客户端通知
        socketServer.sendTaskMsgToAll(noticesList);

        //刷新oa待办
        for (XtzyUser xtzyUser : noticesList) {
            fltdNoticeService.sendMsg(xtzyUser.getUserCode(), xtzyUser.getUserDesc());
        }*/
    }

    /**
     * 提交后的处理（异步）
     */
    private void afterSubmit(Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap, Map<String, Object> params) {
        //后置处理（无事务）
        afterHandle(nodeHandlerMap, params);

    }

    @Override
    public void doCancel(XtzyUser user, FltdTaskVO taskVO) throws Exception {
        Date now = null;
        //需要撤销的待办
        List<FltdTask> cancelTasks = fltdTaskService.selectCancelTask(taskVO.getTodoGuid(), taskVO.getProcGuid(), user.getUserCode());
        if (cancelTasks == null || cancelTasks.size() == 0) {
            throw new Exception("没有可以撤销的待办");
        }
        List<Map<String, Object>> submitList = new ArrayList<>();
        //撤回前验证
        XtzyUser u = new XtzyUser();
        u.setUserCode(cancelTasks.get(0).getCurrUserCode());
        Map<String, Object> resultMap = batchCancels(taskVO, user, u, submitList);
        if (!"0".equals(resultMap.get("code"))) {
            throw new Exception((String) resultMap.get("msg"));
        }

        for (FltdTask cancelTask : cancelTasks) {
            XtzyUser cancelUser = new XtzyUser();
            cancelUser.setUserCode(cancelTask.getCurrUserCode());
            //修改被撤回的待办状态
            now = new Date();
            cancelTask.setStatus("finish");
            cancelTask.setStatusName("关闭");
            cancelTask.setUpdateBy(user.getUserCode());
            cancelTask.setUpdateTime(now);
            int result = fltdTaskService.updateTaskStatus(cancelTask);
            if (result == 0) {
                throw new Exception("数据库操作异常！");
            }
        }

        //当前审批人的待办
        FltdTask currentTask = fltdTaskService.selectTaskByTodoGuid(taskVO.getTodoGuid());

        //修改流程实例表状态
        now = new Date();
        FltdProcess updateProcess = new FltdProcess();
        updateProcess.setProcGuid(currentTask.getProcGuid());
        updateProcess.setNodeCode(currentTask.getNodeCode());
        updateProcess.setNodeName(currentTask.getNodeName());
        updateProcess.setUpdateBy(user.getUserCode());
        updateProcess.setUpdateTime(now);
        int result = updateProcessStatus(updateProcess);
        if (result == 0) {
            throw new Exception("数据库操作异常！");
        }

        //添加一条撤回的待办历史
        now = new Date();
        FltdTask cancelHistory = new FltdTask();
        BeanUtils.copyBeanProp(cancelHistory, currentTask);
        cancelHistory.setTodoGuid(UUID.randomUUID().toString());
        cancelHistory.setFactEndDate(now);
        cancelHistory.setAuditCode(user.getUserCode());
        cancelHistory.setAuditName(user.getUserDesc());
        cancelHistory.setStatus("close");
        cancelHistory.setStatusName("完成");
        cancelHistory.setCreateBy(user.getUserCode());
        cancelHistory.setCreateTime(now);
        cancelHistory.setUpdateBy(null);
        cancelHistory.setUpdateTime(null);
        cancelHistory.setContext(taskVO.getContext());
        cancelHistory.setRemark(WorkflowConstant.COMMENT_CANCEL);
        result = fltdTaskService.insert(cancelHistory);
        if (result == 0) {
            throw new Exception("数据库操作异常！");
        }

        //给当前审批人重新下发待办
        now = new Date();
        FltdTask fltdTask = new FltdTask();
        BeanUtils.copyBeanProp(fltdTask, currentTask);
        fltdTask.setTodoGuid(UUID.randomUUID().toString());
        fltdTask.setStatus("open");
        fltdTask.setStatusName("进行中");
        fltdTask.setAuditCode(null);
        fltdTask.setAuditName(null);
        fltdTask.setFactEndDate(null);
        fltdTask.setContext(null);
        fltdTask.setRemark(WorkflowConstant.COMMENT_REJECT);
        fltdTask.setCreateBy(user.getUserCode());
        fltdTask.setCreateTime(now);
        fltdTask.setUpdateBy(null);
        fltdTask.setUpdateTime(null);
        fltdTask.setGreenFlag("N");
        fltdTask.setExt1("2");
        fltdTask.setExt2(WorkflowConstant.COMMENT_REJECT);
        result = fltdTaskService.insert(fltdTask);
        if (result == 0) {
            throw new Exception("数据库操作异常！");
        }

        //查询当前节点的事件配置
        Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap = getNodeHandler(currentTask.getFlowNo(), currentTask.getNodeCode());

        //事件的参数
        Map<String, Object> params = new HashMap<>();
        params.put("status", currentTask.getNodeCode());
        params.put("nextStatus", currentTask.getBeforeNodeCode());
        params.put("nextStatusName", currentTask.getBeforeNodeName());
        params.put("acctYear", currentTask.getAcctYear());
        params.put("quarterCurrent", currentTask.getQuarterCode());
        params.put("deptCode", currentTask.getDeptCode());
        params.put("bizGuid", currentTask.getBizGuid());
        params.put("taskGuid", currentTask.getTaskGuid());

        //前置处理
        if (!beforeHandle(nodeHandlerMap, params)) {
            throw new Exception("前置处理异常！");
        }

        //状态修改
        if (!updateHandle(nodeHandlerMap, params)) {
            throw new Exception("前置处理异常！");
        }

        String status = returnsProcess(submitList);
        if (!"1".equals(status)) {
            //撤回失败，可能已经被提交
            throw new Exception("撤回失败，可能已经被提交！");
        }

        //同步OA
        for (FltdTask cancelTask : cancelTasks) {
        	fltdOATaskService.deleteOA(cancelTask);
        }

        //后置处理
        afterHandle(nodeHandlerMap, params);

        //发送客户端通知
        List<XtzyUser> userList = new ArrayList<>();
        XtzyUser xtzyUser = new XtzyUser();
        xtzyUser.setUserCode(fltdTask.getAuditCode());
        xtzyUser.setUserDesc(fltdTask.getAuditName());
        xtzyUser.setExt1(fltdTask.getDeptCode());
        xtzyUser.setExt2(fltdTask.getDeptName());
        userList.add(xtzyUser);
        socketServer.sendTaskMsgToAll(userList);
    }

    @Override
    public void doReassign(XtzyUser user, FltdTaskVO taskVO) throws Exception {
        try {
            Date now = new Date();
            //受理人
            String assigneeUserCode = taskVO.getCurrUserCode();
            String assigneeUserName = taskVO.getCurrUserName();
            if (StringUtils.isEmpty(assigneeUserCode)) {
                throw new Exception("受理人不能为空");
            }

            //查询当前待办信息
            FltdTask currentTask = fltdTaskService.selectTaskByTodoGuid(taskVO.getTodoGuid());
            if (currentTask == null) {
                throw new Exception("没有未处理的待办！");
            }

            // 关闭当前处理人的待办
            FltdTask update = (FltdTask) BeanUtils.updateBean(new FltdTask());
            update.setTodoGuid(currentTask.getTodoGuid());
            update.setStatus("close");
            update.setStatusName("完成");
            update.setAuditCode(assigneeUserCode);
            update.setAuditName(assigneeUserName);
            update.setFactEndDate(now);
            if(fltdTaskService.updateByPrimaryKeySelective(update) < 1) {
                throw new Exception("数据库操作异常！");
            }

            // 给受理人下发待办
            FltdTask fltdTask = (FltdTask) BeanUtils.initBean(new FltdTask());
            BeanUtils.copyBeanProp(fltdTask, currentTask);
            fltdTask.setTodoGuid(UUID.randomUUID().toString());
            fltdTask.setCurrUserCode(assigneeUserCode);
            fltdTask.setCurrUserName(assigneeUserName);
            fltdTask.setRemark(WorkflowConstant.COMMENT_REASSIGN);
            fltdTask.setExt1("4");
            fltdTask.setExt2(WorkflowConstant.COMMENT_REASSIGN);
            fltdTask.setUpdateBy(null);
            fltdTask.setUpdateTime(null);
            if (fltdTaskService.insert(fltdTask) < 1) {
                throw new Exception("数据库操作异常！");
            }

            Map<String, Object> resultMap = reassignTask(taskVO.getProcGuid(), taskVO.getRemark(), currentTask.getCurrUserCode(), assigneeUserCode);
            if (!"1".equals(resultMap.get("status"))) {
                throw new Exception("待办移交异常！");
            }

            // 给自己和受理人发送通知
            List<XtzyUser> userList = new ArrayList<>();
            user.setExt1(taskVO.getDeptCode());
            user.setExt3("close");
            userList.add(user);
            XtzyUser assignUser = new XtzyUser();
            assignUser.setUserCode(assigneeUserCode);
            assignUser.setUserDesc(assigneeUserName);
            assignUser.setExt1(taskVO.getDeptCode());
            assignUser.setExt3("open");
            userList.add(assignUser);
            sendNotice(userList);
        } catch (Exception e) {
            throw new Exception("待办移交异常："+ e.getMessage());
        }

    }

    /**
     * 启动流程
     *
     * @param sysUser    当前用户
     * @param processKey 流程编码
     * @param variables  流程变量
     * @return 接口调用结果
     */
    private Map<String, Object> startProcess(XtzyUser sysUser, String processKey, Map<String, Object> variables) {
        Map<String, Object> resultMap = new HashMap<>();
        try {
            String starterId = sysUser.getUserCode();

            EiInfo inInfo = new EiInfo();
            //流程定义编码
            inInfo.set("processDefinitionKey", processKey);
            //流程启动者ID
            inInfo.set("starterId", starterId);
            //流程实例的全局变量
            inInfo.set("variables", variables);
            //下一步审批人(流程下发人)
            List<XtzyUser> userList = new ArrayList<>();
            userList.add(sysUser);
            inInfo.set("nextActivityUserList", convertUserList(userList));
            //启动流程实例
            inInfo.set(EiConstant.serviceName, "EW11");
            inInfo.set(EiConstant.methodName, "startProcess");
            EiInfo outInfo = XLocalManager.call(inInfo);
            String processInstanceId = outInfo.getString("processInstanceId");
            resultMap.put("code", "0");
            resultMap.put("msg", "流程实例启动成功");
            resultMap.put("processInstanceId", processInstanceId);
        } catch (Exception e) {
            resultMap.put("code", "1");
            resultMap.put("msg", e.getMessage());
        }
        return resultMap;
    }

    /**
     * 流程提交前验证
     *
     * @param taskVO      流程任务vo
     * @param currentUser 当前用户
     * @return 接口调用结果
     */
    private Map<String, Object> preSubmit(FltdTaskVO taskVO, XtzyUser currentUser) {
        Map<String, Object> resultMap = new HashMap<>();
        String userCode = currentUser.getUserCode();
        FlaaNodeAuthoVO nodeInfo = null;
        List<XtzyUser> userList = null;
        Map<String, Object> variables = taskVO.getVariables() == null ? new HashMap<>() : taskVO.getVariables();
        List<Map<String, Object>> submitList = new ArrayList<>();

        //当前待办
        FltdTask currentTask = fltdTaskService.selectTaskByTodoGuid(taskVO.getTodoGuid());
        resultMap.put("currentTask", currentTask);

        String taskId = getTaskId(currentUser, currentTask.getProcGuid());
        if (StringUtils.isEmpty(taskId)) {
            resultMap.put("code", "1");
            resultMap.put("msg", "没有可以提交的任务！");
            return resultMap;
        }

        //流程提交的参数
        Map<String, Object> map = new HashMap<>();
        map.put("taskId", taskId);
        map.put("userId", userCode);
        map.put("comment", taskVO.getRemark());
        map.put("variables", variables);

        //当前流程定义id
        String processDefId = getProcessDefId(currentTask.getProcGuid());
        if (StringUtils.isEmpty(processDefId)) {
            resultMap.put("code", "5");
            resultMap.put("msg", "流程定义错误！");
            return resultMap;
        }
        resultMap.put("taskId", taskId);
        resultMap.put("processDefId", processDefId);

        //页面点击的审批按钮
        NodeTransitionVO nextTransition = taskVO.getSubmitButton();
        String nodeType = nextTransition.getNodeType();
        String conditionCode = nextTransition.getConditionCode();
        String transitionKey = nextTransition.getTransitionKey();
        variables.put("shiftCondition", transitionKey);
        //绿色按钮
        String greenFlag = currentTask.getGreenFlag();
        //截取页面按钮得参数
        if (!ObjectUtils.isEmpty(taskVO.getSubmitButton())){
            if (!ObjectUtils.isEmpty(taskVO.getSubmitButton().getConditionCode())){
                String submitButton=taskVO.getSubmitButton().getConditionCode();
                if (submitButton.indexOf("greeFlag==")>0 && submitButton.length()>submitButton.indexOf("greeFlag==")+11){
                    String stringGreenFlag=submitButton.substring(submitButton.indexOf("greeFlag==")+11).replace("\"","").trim();
                    if (!ObjectUtils.isEmpty(stringGreenFlag)){
                        greenFlag=stringGreenFlag;
                    }
                }
            }
        }
        variables.put("greeFlag", greenFlag);

        //默认提交操作
        String optionType = WorkflowConstant.OPERATION_SUBMIT;
        if (transitionKey.contains(WorkflowConstant.OPERATION_SUBMIT) || transitionKey.contains("Transition1")) {
            map.put("approvalResult", WorkflowConstant.COMMENT_SUBMIT);
            resultMap.put("approvalResult", WorkflowConstant.COMMENT_SUBMIT);
        } else {
            optionType = WorkflowConstant.OPERATION_RETURN;
            map.put("approvalResult", WorkflowConstant.COMMENT_REJECT);
            resultMap.put("approvalResult", WorkflowConstant.COMMENT_REJECT);
        }

        //下一个节点是条件分支
        if (WorkflowConstant.PROCESS_INCLUSIVEGATEWAY.equals(nodeType)) {
            //校验点击的按钮是否通过转移条件
            Map<String, Object> conditionMap = new HashMap<>();
            //转移线编码
            conditionMap.put("transitionKey", transitionKey);
            //转移条件
            conditionMap.put("conditionCode", conditionCode);
            //JUEL表达式校验
            validCondition(conditionMap, variables);
            if (!(boolean) conditionMap.get("isValid")) {
                resultMap.put("code", "6");
                resultMap.put("msg", "流程线转移规则定义错误！");
                return resultMap;
            }
        }

        //刷新当前转移线
        nextTransition = flaaNodeAuthoService.selectTransitionById(nextTransition.getTransitionDefId(),nextTransition.getProcessDefId());

        //提交操作
        if (WorkflowConstant.OPERATION_SUBMIT.equals(optionType)) {
            //下一个节点的授权信息
            nodeInfo = flaaNodeAuthoService.selectNodeInfo(currentTask.getFlowNo(), nextTransition.getNodeKey());
            if (WorkflowConstant.PROCESS_END.equals(nextTransition.getNodeType())) {
                //下一个节点是结束节点
                resultMap.put("nextTransition", nextTransition);
                submitList.add(map);
                resultMap.put("submitList", submitList);
                resultMap.put("nodeInfo", nodeInfo);
                resultMap.put("code", "0");
                resultMap.put("isEnd", "1");
                return resultMap;
            }
            if (nodeInfo == null) {
                resultMap.put("code", "3");
                resultMap.put("msg", "下一个节点未授权！当前部门：" + currentTask.getDeptName() + "，bizName：" + currentTask.getBizName());
                return resultMap;
            }
            //页面选中的审批人
            userList = taskVO.getCustomUsers();
            if (userList == null || userList.size() == 0) {
                resultMap.put("code", "4");
                resultMap.put("msg", "下一个节点未配置待办审批人！当前部门：" + currentTask.getDeptName() + "，bizName：" + currentTask.getBizName());
                return resultMap;
            }
        }
        //退回操作
        else {
            //被退回节点的待办任务
            FltdTask beforeTask = fltdTaskService.selectBeforeTask(currentTask.getProcGuid(), nextTransition.getNodeKey());
            if (beforeTask == null) {
                resultMap.put("code", "7");
                resultMap.put("msg", "流程定义错误！");
                return resultMap;
            }
            //被退回节点的授权信息
            nodeInfo = flaaNodeAuthoService.selectNodeInfo(beforeTask.getFlowNo(), beforeTask.getNodeCode());
            if (nodeInfo == null) {
                resultMap.put("code", "3");
                resultMap.put("msg", "下一个节点未授权！当前部门：" + currentTask.getDeptName() + "，bizName：" + currentTask.getBizName());
                return resultMap;
            }
            //被退回的用户
            userList = new ArrayList<>();
            XtzyUser xtzyUser = new XtzyUser();
            xtzyUser.setUserCode(beforeTask.getAuditCode());
            xtzyUser.setUserDesc(beforeTask.getAuditName());
            xtzyUser.setExt1(beforeTask.getDeptCode());
            xtzyUser.setExt2(beforeTask.getDeptName());
            userList.add(xtzyUser);
        }

        map.put("nextActivityUserList", convertUserList(userList));
        submitList.add(map);
        resultMap.put("code", "0");
        resultMap.put("submitList", submitList);
        resultMap.put("nodeInfo", nodeInfo);
        resultMap.put("nextTransition", nextTransition);
        resultMap.put("userList", userList);
        return resultMap;
    }

    /**
     * 批量撤回
     *
     * @param taskVO      流程任务vo
     * @param currentUser 当前用户
     * @param cancelUser  被撤回的用户
     * @return 接口调用结果
     */
    private Map<String, Object> batchCancels(FltdTaskVO taskVO, XtzyUser currentUser, XtzyUser cancelUser, List<Map<String, Object>> submitList) {
        Map<String, Object> resultMap = new HashMap<>();
        //被撤回用户的taskid
        String taskId = getTaskId(cancelUser, taskVO.getProcGuid());

        if (StringUtils.isEmpty(taskId)) {
            resultMap.put("code", "1");
            resultMap.put("msg", "没有可以撤回的任务！");
            return resultMap;
        }

        //执行撤回的用户
        String userId = currentUser.getUserCode();
        Map<String, Object> map = new HashMap<>();
        map.put("taskId", taskId);
        map.put("userId", userId);
        map.put("comment", taskVO.getRemark());
        map.put("approvalResult", WorkflowConstant.CANCEL);
        submitList.add(map);
        resultMap.put("code", "0");
        return resultMap;
    }

    /**
     * 任务移交
     *
     * @param processInstanceId 当前流程实例id
     * @param comment           附言
     * @param currentUser       当前用户
     * @param assigneeUser      受理用户
     * @return 接口调用结果
     */
    private Map<String, Object> reassignTask(String processInstanceId, String comment, String currentUser, String assigneeUser) {
        Map<String, Object> resultMap = new HashMap<>();

        EiInfo inInfo = new EiInfo();
        List<Map<String, String>> list = new ArrayList<>();
        Map<String, String> map = new HashMap<>();
        map.put("userId", currentUser);
        map.put("assignee", assigneeUser);
        map.put("comment", comment);
        map.put("processInstanceId", processInstanceId);
        list.add(map);
        inInfo.set("list", list);
        inInfo.set(EiConstant.serviceName, "EW11");
        inInfo.set(EiConstant.methodName, "batchReassignTasks");
        EiInfo outInfo = XLocalManager.call(inInfo);
        int status = outInfo.getStatus();

        resultMap.put("code", "0");
        resultMap.put("status", "" + status);
        return resultMap;
    }


    /**
     * 流程提交
     */
    private EiInfo submitProcess(List<Map<String, Object>> submitList) {
        EiInfo inInfo = new EiInfo();
        inInfo.set("list", submitList);
        inInfo.set(EiConstant.serviceName, "EW11");
        inInfo.set(EiConstant.methodName, "batchSubmit");
        EiInfo outInfo = XLocalManager.call(inInfo);
        return outInfo;
    }

    /**
     * 提交成功，增加积分
     */
    @Log(integralType = IntegralType.Type14)
    private void addIntegral(){}

    /**
     * 流程回退
     */
    private String returnsProcess(List<Map<String, Object>> submitList) {
        EiInfo inInfo = new EiInfo();
        inInfo.set("list", submitList);
        inInfo.set(EiConstant.serviceName, "EW11");
        inInfo.set(EiConstant.methodName, "batchReturns");
        EiInfo outInfo = XLocalManager.call(inInfo);
        return "" + outInfo.getStatus();
    }


    /**
     * 修改流程实例状态
     *
     * @param fltdProcess 流程实例
     * @return 执行结果
     */
    @Override
    public int updateProcessStatus(FltdProcess fltdProcess) {
        return fltdProcessMapper.updateProcessStatus(fltdProcess);
    }

    /**
     * 获取用户当前流程实例的任务id
     *
     * @param sysUser           当前用户
     * @param processInstanceId 流程实例id
     * @return 任务id
     */
    @Override
    public String getTaskId(XtzyUser sysUser, String processInstanceId) {
        String userCode = sysUser.getUserCode();
        List<Task> taskList = getTaskService().createTaskQuery().taskAssignee(userCode).list();
        for (Task task : taskList) {
            String instanceId = task.getProcessInstanceId();
            if (processInstanceId.equals(instanceId)) {
                return task.getId();
            }
        }
        return "";
    }

    /**
     * 获取流程定义id
     *
     * @param processInstanceId 流程实例id
     * @return 流程定义id
     */
    @Override
    public String getProcessDefId(String processInstanceId) {
        ProcessInstanceQuery query= getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId);
        ProcessInstance pi =  query.singleResult();
        return pi.getProcessDefinitionId();
    }

    /**
     * 转换人员列表
     *
     * @param userList 人员列表
     * @return 转换结果
     */
    public List<Map<String, String>> convertUserList(List<XtzyUser> userList) {
        List<Map<String, String>> nextActivityUserList = new ArrayList<>();
        for (XtzyUser user : userList) {
            Map<String, String> nextAuditUser = new HashMap<>();
            nextAuditUser.put("userId", user.getUserCode());
            nextAuditUser.put("userName", user.getUserDesc());
            nextActivityUserList.add(nextAuditUser);
        }
        return nextActivityUserList;
    }

    /**
     * 转换扩展属性
     *
     * @param flowNo    流程编码
     * @param nodeCode  节点编码
     * @param variables 扩展属性map
     * @return 转换结果
     */
    @Override
    public boolean convertExt(String flowNo, String nodeCode, Map<String, Object> variables) {
        try {
            List<FlaaNodeVO> flaaNodeVOS = flaaNodeService.selectFlowNode(flowNo, nodeCode);
            if (flaaNodeVOS != null) {
                for (FlaaNodeVO flaaNodeVO : flaaNodeVOS) {
                    variables.put(flaaNodeVO.getExt1(), flaaNodeVO.getExt2());
                }
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 验证转移条件是否通过
     *
     * @param conditionMap 转移条件
     * @param variables    流程变量
     */
    public void validCondition(Map<String, Object> conditionMap, Map<String, Object> variables) {
        String conditionCode = (String) conditionMap.get("conditionCode");
        if (StringUtils.isNotEmpty(conditionCode)) {
            try {
                conditionMap.put("isValid", false);
                ExpressionFactory factory = new ExpressionFactoryImpl();
                SimpleContext context = new SimpleContext();
                //从流程变量中查找可以满足转移条件的变量
                for (String key : variables.keySet()) {
                    factory.createValueExpression(context, "#{" + key + "}", String.class).setValue(context, variables.get(key));
                }
                ValueExpression expr = factory.createValueExpression(context, "${" + conditionCode + "}", boolean.class);
                if ((boolean) expr.getValue(context)) {
                    conditionMap.put("isValid", expr.getValue(context));
                }
            } catch (Exception e) {
                conditionMap.put("isError", e.getMessage());
            }
        } else {
            conditionMap.put("isValid", false);
        }
    }

    /**
     * 分类排序节点事件
     *
     * @param flowNo   流程编码
     * @param nodeCode 节点编码
     */
    private Map<String, List<FlaaFlowCheckVO>> getNodeHandler(String flowNo, String nodeCode) {
        Map<String, List<FlaaFlowCheckVO>> map = new HashMap<>();
        List<FlaaFlowCheckVO> flaaFlowCheckVOS = flaaFlowCheckService.selectFlowCheck(flowNo, nodeCode);
        //分类
        for (FlaaFlowCheckVO checkVO : flaaFlowCheckVOS) {
            if (map.containsKey(checkVO.getCheckType())) {
                List<FlaaFlowCheckVO> list = map.get(checkVO.getCheckType());
                list.add(checkVO);
            } else {
                List<FlaaFlowCheckVO> list = new ArrayList<>();
                list.add(checkVO);
                map.put(checkVO.getCheckType(), list);
            }
        }

        //排序
        for (String key : map.keySet()) {
            List<FlaaFlowCheckVO> list = map.get(key);
            Collections.sort(list, (o1, o2) -> {
                return o1.getRowOrder() - o2.getRowOrder();
            });
        }
        return map;
    }




    /**
     * 状态修改（大多数情况，有事务处理）
     */
    private boolean updateHandle(Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap, Map<String, Object> params) {
        List<FlaaFlowCheckVO> updateHandleList = nodeHandlerMap.get("Z");
        if (updateHandleList != null) {
            for (FlaaFlowCheckVO checkVO : updateHandleList) {
                UpdateHandler bean = applicationContext.getBean(checkVO.getClassName(), UpdateHandler.class);
                if (bean == null || !bean.updateStatus(params)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 前置处理（少数情况，有事务处理）
     */
    private boolean beforeHandle(Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap, Map<String, Object> params) {
        List<FlaaFlowCheckVO> beforeHandleList = nodeHandlerMap.get("Q");
        if (beforeHandleList != null) {
            for (FlaaFlowCheckVO checkVO : beforeHandleList) {
                BeforeHandler bean = applicationContext.getBean(checkVO.getClassName(), BeforeHandler.class);
                if (bean == null || !bean.doBefore(params)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 后置处理（少数情况，建议做不需要事务控制的事情）
     */
    private boolean afterHandle(Map<String, List<FlaaFlowCheckVO>> nodeHandlerMap, Map<String, Object> params) {
        List<FlaaFlowCheckVO> afterHandleList = nodeHandlerMap.get("H");
        if (afterHandleList != null) {
            try {
                for (FlaaFlowCheckVO checkVO : afterHandleList) {
                    AfterHandler bean = applicationContext.getBean(checkVO.getClassName(), AfterHandler.class);
                    if (bean == null || !bean.doAfter(params)) {
                        return false;
                    }
                }
            } catch (Exception e) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取审批人的授权信息
     */
    private Map<String, Map<String, String>> getUserAuthoInfo(FlaaNodeAuthoVO nodeInfo, XtzyUser currentUser, FltdTaskVO currentTask) throws Exception {
        Map<String, Map<String, String>> resultMap = new HashMap<>();
        try {
            List<FlaaNodeAuthoTypeVO> authoList = nodeInfo.getAuthoList();
            for (FlaaNodeAuthoTypeVO authoTypeVO : authoList) {
                if ("1".equals(authoTypeVO.getTodoType())) {
                    //流程参与者
                    List<XtzyUser> xtzyUserList = new ArrayList<>();
                    Map<String, Object> param = new HashMap<>();
                    param.put("authInfo", authoTypeVO);
                    param.put("currentUser", currentUser);
                    param.put("currentTask", currentTask);
                    param.put("userList", xtzyUserList);
                    authoTypeService.parse(authoTypeVO.getAuthoRange(), param);
                    if (CollectionUtils.isNotEmpty(xtzyUserList)) {
                        for (XtzyUser xtzyUser : xtzyUserList) {
                            Map<String, String> autho = new HashMap<>();
                            autho.put("todoType", authoTypeVO.getTodoType());
                            autho.put("todoTypeName", authoTypeVO.getTodoTypeName());
                            autho.put("pageUrl", authoTypeVO.getPageUrl());
                            resultMap.put(xtzyUser.getUserCode(), autho);
                        }

                    }
                }
            }
        } catch (Exception e) {
            throw new Exception("获取审批人授权信息失败："+e.getMessage());
        }
        return resultMap;
    }

    /**
     * 下发待办
     *
     * @param nodeInfo    当前节点授权规则
     * @param vo          流程任务vo
     * @param currentUser 当前用户
     * @param userList    下一步审批人
     * @return 执行结果
     */
    private Map<String, Object> createTask(FlaaNodeAuthoVO nodeInfo, FltdTaskVO vo, XtzyUser currentUser, List<XtzyUser> userList, String greeFlag, String createType, Map<String, Map<String, String>> userAuthoMap) {
        Map<String, Object> map = new HashMap<>();
        Date now = new Date();
        FltdTask taskParam=new FltdTask();
        List<SysOperLog> operLogList = new ArrayList<>();

        if (!"start".equals(createType)) {
            vo.setStatus("open");
            vo.setStatusName("进行中");
        }
        Map<String, Object> variables = new HashMap<>();
        convertExt(nodeInfo.getFlowNo(), nodeInfo.getNodeCode(), variables);
        String groupFlag = (String) variables.get("groupFlag");
        if (StringUtils.isNotEmpty(groupFlag)) {
            vo.setGroupFlag(groupFlag);
        } else {
            vo.setGroupFlag("N");
        }

        if (userAuthoMap == null) {
            vo.setTodoType(nodeInfo.getTodoType());
            vo.setTodoTypeName(nodeInfo.getTodoTypeName());
            vo.setPageUrl(nodeInfo.getPageUrl());
        }

        vo.setNodeCode(nodeInfo.getNodeCode());
        vo.setNodeName(nodeInfo.getNodeName());
        vo.setFactStartDate(now);
        vo.setCreateBy(currentUser.getUserCode());
        vo.setCreateTime(now);

        for (XtzyUser xtzyUser : userList) {
            try {
                FltdTask task = new FltdTask();
                //转换bean
                BeanUtils.copyBeanProp(task, vo);
                if (userAuthoMap != null) {
                    Map<String, String> authoMap = userAuthoMap.get(xtzyUser.getUserCode());
                    if (authoMap != null) {
                        task.setTodoType(authoMap.get("todoType"));
                        task.setPageUrl(authoMap.get("pageUrl").trim());
                    }
                }
                task.setTodoGuid(UUID.randomUUID().toString());
                if (StringUtils.isNotEmpty(vo.getBizName())) {
                    task.setBizName(vo.getBizName());
                }
                if (StringUtils.isNotEmpty(vo.getBizDesc())) {
                    task.setBizDesc(vo.getBizDesc());
                }
                //判断是否为结题能力测评
                List<String> nodeCodeList = new ArrayList<>(Arrays.asList("B04","B05","B06"));
                if (("fengxianjieticeping".equals(nodeInfo.getFlowNo()) || "jidijieticeping".equals(nodeInfo.getFlowNo())) && (nodeCodeList.contains(nodeInfo.getNodeCode()))){
                    task.setTodoType(nodeInfo.getTodoType());
                    task.setPageUrl(nodeInfo.getPageUrl());
                }
                task.setFirstUserCode(xtzyUser.getUserCode());
                task.setFirstUserName(xtzyUser.getUserDesc());
                task.setCurrUserCode(xtzyUser.getUserCode());
                task.setCurrUserName(xtzyUser.getUserDesc());
                XtzyCompany customCompany = vo.getCustomCompany();
                if (customCompany != null) {
                    task.setDeptCode(customCompany.getCompCode());
                    task.setDeptName(customCompany.getCompName());
                }
                task.setGreenFlag(greeFlag);
                map.put(xtzyUser.getUserCode(), task);
                if (fltdTaskService.insert(task) == 0) {
                    throw new Exception("待办发送失败");
                }
                //提交开始新的ao待办
                if("open".equals(task.getStatus())){
                    try {
                        //todo 正式环境 暂时把OA关闭
                        fltdOATaskService.insertOA(task);
                    }catch (Exception e){
                        operLogList.add(getLog(vo.getBizDesc(), 1, "待办发送失败：" +e.getMessage(), null));
                    }
                }
                operLogList.add(getLog(vo.getBizDesc(), 0, "待办发送成功，待办责任人：" + xtzyUser.getUserCode() + "-" + xtzyUser.getUserDesc(), null));
            } catch (Exception e) {
                operLogList.add(getLog(vo.getBizDesc(), 1, "待办发送失败，待办责任人：" + xtzyUser.getUserCode() + "-" + xtzyUser.getUserDesc(), null));
            }
        }
        // 保存日志到数据库
        AsyncManager.me().execute(AsyncFactory.batchRecordOper(operLogList));
        return map;
    }

    /**
     * 操作日志
     *
     * @param status  操作状态（0正常 1异常）
     * @param message 错误消息
     * @param jobId   任务id
     */
    @Override
    public SysOperLog getLog(String title, int status, String message, String jobId) {
        SysOperLog log = (SysOperLog) BeanUtils.initBean(new SysOperLog());
        log.setTitle(title);
        //业务类型（0其它 1新增 2修改 3删除 4工作流）
        log.setBusinessType(4);
        log.setErrorMsg(message);
        log.setStatus(status);
        log.setExt1(jobId);
        return log;
    }

    @Override
    public String selectDecideType(String processDefId, String nodeKey) {
        return fltdProcessMapper.selectDecideType(processDefId, nodeKey);
    }

    /**
     * 合并、去重用户
     *
     */
    public List<XtzyUser> unionUsers(List<XtzyUser> list, XtzyUser user){
        list.add(user);
        return unionUsers(list);
    }

    /**
     * 合并、去重用户
     *
     */
    public List<XtzyUser> unionUsers(List<XtzyUser> list, List<XtzyUser> users){
        list.addAll(users);
        return unionUsers(list);
    }

    /**
     * 去重用户
     *
     */
    public List<XtzyUser> unionUsers(List<XtzyUser> list){
        List<XtzyUser> result = new ArrayList<>();
        Map<String, XtzyUser> map = new HashMap<>();
        for (XtzyUser u : list) {
            map.put(u.getUserCode(), u);
        }
        for (String key : map.keySet()) {
            if (StringUtils.isNotEmpty(key)) {
                result.add(map.get(key));
            }
        }
        return result;
    }

	@Override
	@Transactional
	public void shiftProcess(String compCode, String newUserCode, String oldUserCode) throws Exception {
		XtzyUser newUser = xtzyUserService.selectByName(newUserCode);
		XtzyUser oldUser = xtzyUserService.selectByName(oldUserCode);

		FltdTask param = new FltdTask();
		param.setCurrUserCode(oldUserCode);
		param.setStatus("open");
		param.setTodoType("1");
		List<FltdTask> tasks = fltdTaskMapper.select(param);
		for(FltdTask task : tasks){
			FltdTaskVO taskVO = new FltdTaskVO();
			taskVO.setTodoGuid(task.getTodoGuid());
			taskVO.setProcGuid(task.getProcGuid());
			taskVO.setCurrUserCode(newUserCode);
			taskVO.setCurrUserName(newUser.getUserDesc());
			this.doReassign(oldUser, taskVO);
		}
	}

	@Override
	public FltdProcess selectProcessByBizGuid(String bizGuid) {
		return fltdProcessMapper.selectProcessByBizGuid(bizGuid);
	}

}
